package chatserver.objects;

import chatserver.sql.MySqlConnection;
import chatserver.container.AutoOpInfo;
import chatserver.container.BanInfo;
import chatserver.netio.AttrList;
import chatserver.netio.Attr;
import chatserver.netio.Perms;
import chatserver.roles.GlobalRole;
import chatserver.roles.Rights;
import chatserver.logging.ServerLog;
import chatserver.netio.Command;
import chatserver.netio.Connection;
import chatserver.netio.ClientAttr;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class User {

    private Connection con;
    // saved variables
    private String name;
    private String[] userInfo;
    private GlobalRole autoRole;
    private String autoRoleBy;
    private String email;
    // session variables
    private boolean isGuest;
    private Date loginTime;
    private Date lastActionTime;
    private Date lastFloodableActionTime;
    private int sqlId;
    private MySqlConnection mySql;
    private boolean hasBirthday;
    private boolean isHidden;
    private ArrayList<Channel> connectedChannels;
    private Server server;
    private GlobalRole role;
    private GlobalRole decidingRole;
    private String lastMessage;
    private int messageRepeatCount;
    private String lcName;
    public static final int AGE = 0;
    public static final int GENDER = 1;
    public static final int CITY = 2;
    public static final int HOMEPAGE = 3;
    public static final int EXTRA = 4;
    public static String PROFILE_BIRTHDAY = "jarig";

    public User(String name, Connection connection) {

        this.server = Server.getInstance();

        this.name = name;
        this.lcName = name.toLowerCase();
        this.con = connection;
        this.isGuest = true;
        this.userInfo = new String[5];
        this.lastMessage = "";
        this.messageRepeatCount = 0;
        for (int i = 0; i < userInfo.length; i++) {
            this.userInfo[i] = "";
        }
        this.role = server.getConfig().getDefaultGlobalRole();
        this.autoRole = this.role;
        this.decidingRole = this.role;
        this.autoRoleBy = "";
        this.email = "";
        this.loginTime = new Date();
        this.lastActionTime = new Date();
        this.lastFloodableActionTime = new Date();
        this.hasBirthday = false;
        this.isHidden = false;
        this.sqlId = -1;
        this.connectedChannels = new ArrayList<Channel>();
        this.mySql = MySqlConnection.getInstance();
    }

    public boolean authenticate(String authName, String password) {
        if (mySql.isUserPasswordCorrect(authName, password)) {
            loadFromSql();
            this.isGuest = false;
            return true;
        } else {
            return false;
        }

    }
    static final String HEXES = "0123456789ABCDEF";

    public static String getHex(byte[] raw) {
        if (raw == null) {
            return null;
        }
        final StringBuilder hex = new StringBuilder(2 * raw.length);
        for (final byte b : raw) {
            hex.append(HEXES.charAt((b & 0xF0) >> 4)).append(HEXES.charAt((b & 0x0F)));
        }
        return hex.toString();
    }

    public boolean authenticate(String authName, byte[] digest, String digestSalt) {
        ServerLog.log("ADZ - User.java->authenticate:digest="+digest+":digestSalt="+digestSalt);
        String sDigest = getHex(digest);

        if (mySql.isUserPasswordCorrect(authName, sDigest, digestSalt)) {
            loadFromSql();
            // ADZ - 
            for (int i = 0; i <this.getUserInfo().length; i++)
                ServerLog.log(i+":"+this.getUserInfo()[i]);
            
            this.isGuest = false;
            return true;
        } else {
            return false;
        }
        

    }

    private void loadFromSql() {
        ServerLog.log("ADZ - User.java->loadFromSql");
        Map<String, String> userData = mySql.loadUserData(name);
        
        GlobalRole aRole = server.getConfig().findGlobalRoleById(Integer.parseInt(userData.get("roleid")));

        this.autoRoleBy = userData.get("roleby");
        this.userInfo[0] = userData.get("age");
        this.userInfo[1] = userData.get("gender");
        this.userInfo[2] = userData.get("city");
        this.userInfo[3] = userData.get("homepage");
        this.userInfo[4] = userData.get("extra");
        this.email = userData.get("email");
        this.sqlId = Integer.parseInt(userData.get("id"));

        setRole(aRole, "Server", true, true);
    }

    private void saveToSql() {
        if (sqlId == -1) {
            return;
        }
        mySql.updateUserData(sqlId, autoRole, autoRoleBy, userInfo, email);
    }

    public void rehash() {
        if (sqlId == -1) {
            return;
        }
        loadFromSql();
    }

    public String getName() {
        return name;
    }

    public String getLowerCaseName() {
        return lcName;
    }

    public void setRole(GlobalRole r, String roleBy, boolean permanent, boolean silent) {

        GlobalRole oldRole = role;
        role = r;

        if (permanent) {
            autoRole = r;
            autoRoleBy = roleBy;
            saveToSql();
        }

        if (role.hasRight(Rights.Global.ServerOp, autoRole.getSqlId())) {
            decidingRole = role;
        } else {
            decidingRole = autoRole;
        }

        if (!silent) {
            Date d = new Date();
            AttrList at = new AttrList();
            at.safeAddClientAttr(ClientAttr.NICKNAME, roleBy);
            at.safeAddClientAttr(ClientAttr.TARGETNAME, getName());
            at.safeAddClientAttr(ClientAttr.PROFILE, getGlobalProfile());
            if (permanent) {
                at.safeAddClientAttr(ClientAttr.PERSISTENT, 1);
            }
            at.safeAddClientAttr(ClientAttr.LOG_TIME, (int) (d.getTime() / 1000));
            Command cmd = new Command(Command.SETPROFILE, at);
            con.sendCommand(cmd);
        }
        
        if(oldRole.getSqlId() != role.getSqlId())
        {
            for(Channel c : connectedChannels)
            {
                c.updatedUserGlobalProfile(this, roleBy);
            }
        }
    }

    public Perms getGlobalPerms() {
        return Perms.getGlobalUserPerms(this);
    }

    public String getGlobalProfile() {

        if (hasBirthday()) {
            return PROFILE_BIRTHDAY;
        }

        return role.getProfile();
    }

    public boolean hasGlobalRight(Rights.Global right) {

        if (right == Rights.Global.HasBoldText && hasBirthday()) {
            return true;
        }

        return decidingRole.hasRight(right);
    }

    public boolean hasGlobalRight(Rights.Global right, int modifier) {

        return decidingRole.hasRight(right, modifier);
    }

    public boolean hasGlobalRightWithAnyModifier(Rights.Global right) {

        return decidingRole.hasRightWithAnyModifier(right);
    }

    public int getDecidingGlobalRoleSqlId() {
        return decidingRole.getSqlId();
    }

    public GlobalRole getDecidingGlobalRole() {
        return decidingRole;
    }

    public String[] getUserInfo() {
        return userInfo;
    }

    public String getUserInfo(int index) {
        if (index < 0 || index > 4) {
            return null;
        }
        return userInfo[index];
    }

    public void setUserInfo(String value, int index) {
        if (index < 0 || index > 4) {
            return;
        }
        if (value != null && !value.equals("")) {
            userInfo[index] = value;
            saveToSql();
        }
    }

    public void setUserInfo(String[] values) {
        if (values.length != 5) {
            return;
        }
        for (int i = 0; i < values.length && i < userInfo.length; i++) {
            String nfo = values[i];
            if (nfo != null && !nfo.equals("")) {
                userInfo[i] = nfo;
            }
        }
        saveToSql();
    }

    public Connection getConnection() {
        return con;
    }

    public boolean isGuest() {
        return isGuest;
    }

    public boolean hasBirthday() {
        return hasBirthday;
    }

    public void setBirthday(boolean b) {
        hasBirthday = b;
    }

    public boolean isHidden() {
        return isHidden;
    }

    public void setHidden(boolean b) {

        if (isHidden != b) {
            isHidden = b;

            Iterator<Channel> iter = connectedChannels.iterator();
            while (iter.hasNext()) {
                Channel c = iter.next();
                c.updateHideStatus(this);
            }
        }
    }

    public int getLoginTime() {
        Date now = new Date();
        return (int) ((now.getTime() - loginTime.getTime()) / 1000);
    }

    public void onChannelClose(Channel c) {
        if (connectedChannels.contains(c)) {
            connectedChannels.remove(c);
        }
    }

    public void onDisconnect() {
        Iterator<Channel> iter = connectedChannels.iterator();
        while (iter.hasNext()) {
            Channel c = iter.next();
            c.onUserDisconnect(this);
        }
        server.onUserDisconnect(this);
        saveToSql();
    }

    public void getMemberInfo(String channelName, String targetName) {
        ServerLog.logWarning(this.con, "tried to get memberInfo");
    }

    public void getChatBoxInfo() {
        String[] cbInfo = new String[1];
        cbInfo[0] = server.getConfig().getChatBoxInfo();

        AttrList at = new AttrList();
        for (int i = 0; i < cbInfo.length; i++) {
            at.safeAddClientAttr(ClientAttr.CHATBOXINFO, cbInfo[i]);
        }
        Command cmd = new Command(Command.CHATBOXINFO, at);
        con.sendCommand(cmd);
    }

    private List<Channel> channelList() {
        return connectedChannels;
    }

    public int getIdleTime() {
        Date now = new Date();
        return (int) ((now.getTime() - lastActionTime.getTime()) / 1000);
    }

    public String getIdleTimeAsString() {
        long Milliseconds = (new Date()).getTime() - lastActionTime.getTime();
        long Hours = Milliseconds / (1000 * 60 * 60);
        long Minutes = (Milliseconds % (1000 * 60 * 60)) / (1000 * 60);
        long Seconds = ((Milliseconds % (1000 * 60 * 60)) % (1000 * 60)) / 1000;

        String ret = "";

        if (Hours > 0) {
            ret += Hours + "h ";
        }
        if (Minutes > 0) {
            ret += Minutes + "m ";
        }

        ret += Seconds + "s";

        return ret;
    }

    public String getIp() {
        return con.getClientIp();
    }

    public void getUserInfo(String targetName) {
        User u = server.findUser(targetName);
        if (u == null) {
            AttrList at = new AttrList();
            at.safeAddClientAttr(ClientAttr.TARGETNAME, targetName);
            Command cmd = new Command(Command.NOTARGET, at);
            con.sendCommand(cmd);
            return;
        }

        if (u.isHidden() && !hasGlobalRight(Rights.Global.AdministrateServer)) {
            AttrList at = new AttrList();
            at.safeAddClientAttr(ClientAttr.TARGETNAME, targetName);
            Command cmd = new Command(Command.NOTARGET, at);
            con.sendCommand(cmd);
            return;
        }

        String[] uInfo = u.getUserInfo();
        AttrList at = new AttrList();
        at.safeAddClientAttr(ClientAttr.NICKNAME, targetName);
        at.safeAddClientAttr(ClientAttr.TARGETNAME, targetName);
        at.safeAddClientAttr(ClientAttr.CONNECTTIME, u.getLoginTime());

        String channels = "";
        boolean first = true;
        Iterator<Channel> iter = u.channelList().iterator();
        while (iter.hasNext()) {
            Channel c = iter.next();
            if (first) {
                channels = c.getName();
                first = false;
            } else {
                channels += ", " + c.getName();
            }
        }
        at.safeAddClientAttr(ClientAttr.CHANNELNAME, channels);

        at.safeAddClientAttr(ClientAttr.IDLETIME, u.getIdleTime());


        if (hasGlobalRight(Rights.Global.ViewIP)) {
            at.safeAddClientAttr(ClientAttr.IP, u.getConnection().getRawIp());
        }

        if (hasGlobalRight(Rights.Global.ViewAlias)) {
            String alias = server.getAliasesOfUser(u);
            if (!"".equals(alias)) {
                at.safeAddClientAttr(ClientAttr.ALIAS, server.getAliasesOfUser(u));
            }
        }

        // at.safeAddClientAttr(ClientAttr.PROXY_IP, "<proxy_ip>");
        // at.safeAddClientAttr(ClientAttr.IDENT, "<ident>");        

        for (int i = 0; i < uInfo.length; i++) {
            at.safeAddClientAttr(ClientAttr.USERINFO, uInfo[i]);
        }
        Command cmd = new Command(Command.USERINFO, at);
        con.sendCommand(cmd);
    }

    public void getChannelInfo(String channelName) {
        Channel c = server.findChannel(channelName);
        if (c == null) {
            AttrList at = new AttrList();
            at.safeAddClientAttr(ClientAttr.CHANNELNAME, channelName);
            Command cmd = new Command(Command.NOCHANNEL, at);
            con.sendCommand(cmd);
            return;
        }

        AttrList at = new AttrList();
        c.getChannelInfo(at);
        Command cmd = new Command(Command.CHANNELINFO, at);
        con.sendCommand(cmd);
    }

    public void getGlobalUserPerms(String targetName) {
        User u = server.findUser(targetName);
        if (u == null) {
            AttrList at = new AttrList();
            at.safeAddClientAttr(ClientAttr.TARGETNAME, targetName);
            Command cmd = new Command(Command.NOTARGET, at);
            con.sendCommand(cmd);
            return;
        }

        AttrList at = new AttrList();
        at.safeAddClientAttr(ClientAttr.NICKNAME, targetName);
        try {
            at.add(u.getGlobalPerms().toAttr(ClientAttr.PERMS));
        } catch (Exception ex) {
        }

        Command cmd = new Command(Command.PERMS, at);
        con.sendCommand(cmd);
    }

    public void getChannelUserPerms(String channelName, String targetName) {
        Channel c = server.findChannel(channelName);
        if (c == null) {
            AttrList at = new AttrList();
            at.safeAddClientAttr(ClientAttr.TARGETNAME, targetName);
            Command cmd = new Command(Command.NOTARGET, at);
            con.sendCommand(cmd);
            return;
        }

        Perms perms = c.getChannelUserPerms(targetName);
        if (perms == null) {
            AttrList at = new AttrList();
            at.safeAddClientAttr(ClientAttr.TARGETNAME, targetName);
            at.safeAddClientAttr(ClientAttr.CHANNELNAME, channelName);
            Command cmd = new Command(Command.NOTARGET, at);
            con.sendCommand(cmd);
            return;
        }

        AttrList at = new AttrList();
        at.safeAddClientAttr(ClientAttr.NICKNAME, targetName);
        at.safeAddClientAttr(ClientAttr.CHANNELNAME, channelName);
        try {
            at.add(perms.toAttr(ClientAttr.PERMS));
        } catch (Exception ex) {
        }
        Command cmd = new Command(Command.PERMS, at);
        con.sendCommand(cmd);
    }

    public void setUserInfo(Attr[] info, Integer index) {
        if (index == null) {
            for (int i = 0; i < 5 && i < info.length; i++) {
                String nfo = info[i].getAsString();
                if (nfo != null && !nfo.equals("")) {
                    userInfo[i] = nfo;
                }
            }
            saveToSql();
        } else {
            if (index >= 0 && index < 5) {
                if (info.length > 0) {
                    String nfo = info[0].getAsString();
                    if (nfo != null && !nfo.equals("")) {
                        userInfo[index] = info[0].getAsString();
                    }
                    saveToSql();
                }
            }
        }
    }

    public void setUserInfo(String targetName, Attr[] info, Integer index) {
        if (targetName.equals(name)) {
            setUserInfo(info, index);
            return;
        }

        User u = server.findUser(targetName);
        if (u == null) {
            AttrList at = new AttrList();
            at.safeAddClientAttr(ClientAttr.TARGETNAME, targetName);
            Command cmd = new Command(Command.NOTARGET, at);
            con.sendCommand(cmd);
            return;
        }


        if (!hasGlobalRight(Rights.Global.ChangeUserInfo, u.getDecidingGlobalRoleSqlId())) {
            Command cmd = new Command(Command.NOPERMISSION);
            con.sendCommand(cmd);
            return;
        }

        u.setUserInfo(info, index);
    }

    public void setMemberInfo(String channelName, String targetName, Attr[] info, Integer index) {
        ServerLog.logWarning(this.con, "tried to set memberInfo");
    }

    public void setChannelInfo(String channelName, Attr[] info, Integer index) {
        if (info.length < 1) {
            return;
        }

        ServerLog.log("ADZ - User.java->setChannelInfo:channelName="+channelName +":attr="+info+":index="+index);
        
        String newTopic = info[0].getAsString();

        Channel c = server.findChannel(channelName);
        if (c == null) {
            AttrList at = new AttrList();
            at.safeAddClientAttr(ClientAttr.CHANNELNAME, channelName);
            Command cmd = new Command(Command.NOCHANNEL, at);
            con.sendCommand(cmd);
            return;
        }

        c.setTopic(this, newTopic);
        //todo: add support for isStatic, isImportant, bgImage
        // and profile?!
    }

    public int getSqlId() {
        return sqlId;
    }

    public void setChatBoxInfo(Attr[] aInfo, Integer index) {
        if (aInfo.length < 1) {
            return;
        }
        String info = aInfo[0].getAsString();

        if (!hasGlobalRight(Rights.Global.AdministrateServer)) {
            Command cmd = new Command(Command.NOPERMISSION);
            con.sendCommand(cmd);
            return;
        }

        server.getConfig().setChatBoxInfo(info);
    }

    public void joinChannel(Channel c) {
        ServerLog.log("ADZ - User.java->joinChannel:Channel="+c);
        updateIdleTime();

        if (connectedChannels.contains(c)) {
            return;
        }

        //if (this.isGuest() && c.getType() == "id")
        //    ;
        //else
        //{
            if (c.join(this)) {
                connectedChannels.add(c);
            }
        //}
    }

    public void createAndJoinChannel(String channelName, String channelType) {
        ServerLog.log("ADZ - User.java->createAndJoinChannel::channelName="+channelName+":channelType="+channelType);
        updateIdleTime();

        if (!hasGlobalRight(Rights.Global.AddChannel)) {
            ServerLog.log("ADZ - Don't have global rights.");
            Command cmd = new Command(Command.NOPERMISSION);
            con.sendCommand(cmd);

            getChannelList();
            return;
        }

        Channel c = server.createChannel(this, channelName, channelType);
        if (c == null) {
            getChannelList();
            return;
        }

        if (c.join(this)) {
            connectedChannels.add(c);
        } else {
            getChannelList();
        }

    }

    public void partChannel(Channel c) {
        updateIdleTime();

        if (connectedChannels.contains(c)) {
            c.part(this);
            connectedChannels.remove(c);
            return;
        } else {
            Command cmd = new Command(Command.NOCHANNEL);
            con.sendCommand(cmd);
            return;
        }
    }

    public void updateIdleTime() {
        lastActionTime = new Date();
    }

    public void sendPrivateNote(String targetName, String noteText, String noteFormat, String noteMe) {
        updateIdleTime();

        if (checkFlood(noteText)) {
            Command cmd = new Command(Command.FLOODING);
            con.sendCommand(cmd);
            return;
        }

        User target = server.findUser(targetName);
        if (target == null) {
            AttrList at = new AttrList();
            at.safeAddClientAttr(ClientAttr.TARGETNAME, targetName);
            Command cmd = new Command(Command.NOTARGET, at);
            con.sendCommand(cmd);
            return;
        }

        if (!hasGlobalRight(Rights.Global.TalkTo)) {
            Command cmd = new Command(Command.NOPERMISSION);
            con.sendCommand(cmd);
            return;
        }

        AttrList at = new AttrList();
        at.safeAddClientAttr(ClientAttr.NICKNAME, name);
        at.safeAddClientAttr(ClientAttr.TARGETNAME, targetName);
        if (noteFormat != null && hasGlobalRight(Rights.Global.UseColor)) {
            at.safeAddClientAttr(ClientAttr.NOTE_FORMAT, noteFormat);
        }
        if (noteMe != null) {
            at.safeAddClientAttr(ClientAttr.NOTE_ME, noteMe);
        }
        at.safeAddClientAttr(ClientAttr.NOTE_TEXT, noteText);

        Command cmd = new Command(Command.NOTE, at);
        target.getConnection().sendCommand(cmd);
        con.sendCommand(cmd);
    }

    public boolean checkFlood(String message) {

        Date now = new Date();

        long checkTime = now.getTime() - lastFloodableActionTime.getTime();

        lastFloodableActionTime = now;

        if (checkTime < server.getConfig().getFloodDelay()) {
            return true;
        }

        if (message.length() > server.getConfig().getFloodMaxLength()) {
            return true;
        }

        for (String msg : message.split(" ")) {
            if (msg.length() > server.getConfig().getFloodMaxWordLength()) {
                return true;
            }
        }

        if (message.toLowerCase().equals(lastMessage)) {
            if (messageRepeatCount < server.getConfig().getFloodMaxRepeat() - 2) {
                messageRepeatCount++;
            } else {
                return true;
            }
        } else {
            messageRepeatCount = 0;
        }

        lastMessage = message.toLowerCase();


        return false;
    }

    public void sendChannelNote(String channelName, String noteText, String noteFormat, String noteMe) {
        updateIdleTime();

        if (checkFlood(noteText)) {
            Command cmd = new Command(Command.FLOODING);
            con.sendCommand(cmd);
            return;
        }

        Channel target = server.findChannel(channelName);
        if (target == null) {
            AttrList at = new AttrList();
            at.safeAddClientAttr(ClientAttr.CHANNELNAME, channelName);
            Command cmd = new Command(Command.NOCHANNEL, at);
            con.sendCommand(cmd);
            return;
        }

        if (!hasGlobalRight(Rights.Global.Talk)) {
            Command cmd = new Command(Command.NOPERMISSION);
            con.sendCommand(cmd);
            return;
        }

        target.note(this, noteText, noteFormat, noteMe);
    }

    public void sendGlobalNote(String noteText, String noteFormat, String noteMe) {
        updateIdleTime();


        if (!hasGlobalRight(Rights.Global.AdministrateServer)) {
            Command cmd = new Command(Command.NOPERMISSION);
            con.sendCommand(cmd);
            return;
        }

        AttrList at = new AttrList();

        //at.safeAddClientAttr(ClientAttr.NICKNAME, name);

        //if (noteFormat != null && hasGlobalRight(Rights.Global.UseColor)) {
        //    if (!noteFormat.contains("C#")) {
        //        noteFormat += "\033C#ff0000;";
        //    }
        //    at.safeAddClientAttr(ClientAttr.NOTE_FORMAT, noteFormat);
        //} else {
        at.safeAddClientAttr(ClientAttr.NOTE_FORMAT, "\033B;\033C#"
                + server.getConfig().getWallColor() + ";");
        //}

        //if (noteMe != null) {
        //    at.safeAddClientAttr(ClientAttr.NOTE_ME, noteMe);
        //}
        at.safeAddClientAttr(ClientAttr.PERSISTENT, 1);
        
        noteText =  "[ " + server.getConfig().getWallMessage() + ": " +  noteText + " ]";
        at.safeAddClientAttr(ClientAttr.NOTE_TEXT, noteText);

        Command cmd = new Command(Command.NOTE, at);
        server.sendToConnectedUsers(cmd);
    }

    public void channelKick(String channelName, String targetName) {
        updateIdleTime();

        Channel c = server.findChannel(channelName);
        if (c == null) {
            AttrList at = new AttrList();
            at.safeAddClientAttr(ClientAttr.CHANNELNAME, channelName);
            Command cmd = new Command(Command.NOCHANNEL, at);
            con.sendCommand(cmd);
            return;
        }

        c.kick(this, targetName);
    }

    public void serverKick(String targetName) {
        updateIdleTime();

        User target = server.findUser(targetName);
        if (target == null) {
            AttrList at = new AttrList();
            at.safeAddClientAttr(ClientAttr.TARGETNAME, targetName);
            Command cmd = new Command(Command.NOTARGET, at);
            con.sendCommand(cmd);
            return;
        }

        if (this == target || !hasGlobalRight(Rights.Global.ServerKick, target.getDecidingGlobalRoleSqlId())) {
            Command cmd = new Command(Command.NOPERMISSION);
            con.sendCommand(cmd);
            return;
        }

        server.kickUser(target);
    }

    public void channelBan(String channelName, String targetName, int ipSize, long expires) {
        updateIdleTime();

        Channel c = server.findChannel(channelName);
        if (c == null) {
            AttrList at = new AttrList();
            at.safeAddClientAttr(ClientAttr.CHANNELNAME, channelName);
            Command cmd = new Command(Command.NOCHANNEL, at);
            con.sendCommand(cmd);
            return;
        }

        User target = server.findUser(targetName);
        if (target == null) {
            AttrList at = new AttrList();
            at.safeAddClientAttr(ClientAttr.TARGETNAME, targetName);
            Command cmd = new Command(Command.NOTARGET, at);
            con.sendCommand(cmd);
            return;
        }

        c.ban(this, target, ipSize, expires, name);
    }

    public void serverBan(String targetName, int ipSize, long expires) {
        updateIdleTime();

        User target = server.findUser(targetName);
        if (target == null) {
            AttrList at = new AttrList();
            at.safeAddClientAttr(ClientAttr.TARGETNAME, targetName);
            Command cmd = new Command(Command.NOTARGET, at);
            con.sendCommand(cmd);
            return;
        }

        if (this == target || !hasGlobalRight(Rights.Global.ServerBan, target.getDecidingGlobalRoleSqlId())) {
            Command cmd = new Command(Command.NOPERMISSION);
            con.sendCommand(cmd);
            return;
        }

        server.addBan(target.getConnection(), target.getName(), ipSize, expires, name);
        server.kickUser(target);

        Date d = new Date();
        AttrList at = new AttrList();
        at.safeAddClientAttr(ClientAttr.NICKNAME, name);
        at.safeAddClientAttr(ClientAttr.TARGETNAME, target.getName());
        at.safeAddClientAttr(ClientAttr.PROFILE, "banned");
        at.safeAddClientAttr(ClientAttr.LOG_TIME, (int) (d.getTime() / 1000));
        Command cmd = new Command(Command.BANNED, at);
        con.sendCommand(cmd);
    }

    public void channelUnBan(String channelName, String targetName) {
        updateIdleTime();

        Channel c = server.findChannel(channelName);
        if (c == null) {
            AttrList at = new AttrList();
            at.safeAddClientAttr(ClientAttr.CHANNELNAME, channelName);
            Command cmd = new Command(Command.NOCHANNEL, at);
            con.sendCommand(cmd);
            return;
        }

        c.unban(this, targetName);
    }

    public void serverUnBan(String targetName) {
        updateIdleTime();

        int targetRoleId = mySql.getGlobalRoleIdOfUser(targetName);

        if (targetRoleId != -1) {

            if (!hasGlobalRight(Rights.Global.ServerBan, targetRoleId)) {
                Command cmd = new Command(Command.NOPERMISSION);
                con.sendCommand(cmd);
                return;
            }

        }

        if (server.delBanByName(targetName)) {
            Date d = new Date();
            AttrList at = new AttrList();
            at.safeAddClientAttr(ClientAttr.NICKNAME, name);
            at.safeAddClientAttr(ClientAttr.TARGETNAME, targetName);
            at.safeAddClientAttr(ClientAttr.PROFILE, "banned");
            at.safeAddClientAttr(ClientAttr.LOG_TIME, (int) (d.getTime() / 1000));
            Command cmd = new Command(Command.UNBANNED, at);
            con.sendCommand(cmd);
        } else {
            AttrList at = new AttrList();
            at.safeAddClientAttr(ClientAttr.TARGETNAME, targetName);
            Command cmd = new Command(Command.NOTARGET, at);
            con.sendCommand(cmd);
            return;
        }
    }

    public void channelOp(String channelName, String targetName, String profile, boolean auto) {
        updateIdleTime();

        Channel c = server.findChannel(channelName);
        if (c == null) {
            AttrList at = new AttrList();
            at.safeAddClientAttr(ClientAttr.CHANNELNAME, channelName);
            Command cmd = new Command(Command.NOCHANNEL, at);
            con.sendCommand(cmd);
            return;
        }

        c.op(this, targetName, server.getConfig().findChannelRoleByProfile(profile), auto);
    }

    public void serverOp(String targetName, String profile, boolean auto) {
        updateIdleTime();

        User target = server.findUser(targetName);
        if (target == null) {
            AttrList at = new AttrList();
            at.safeAddClientAttr(ClientAttr.TARGETNAME, targetName);
            Command cmd = new Command(Command.NOTARGET, at);
            con.sendCommand(cmd);
            return;
        }

        // special profiles start
        if (profile.equals(PROFILE_BIRTHDAY)) {

            if (!hasGlobalRight(Rights.Global.SetBirthday)) {
                Command cmd = new Command(Command.NOPERMISSION);
                con.sendCommand(cmd);
                return;
            }

            target.setBirthday(!target.hasBirthday());

            Iterator<Channel> iter = target.connectedChannels.iterator();
            while (iter.hasNext()) {
                Channel c = iter.next();
                Date d = new Date();
                AttrList at = new AttrList();
                at.safeAddClientAttr(ClientAttr.NICKNAME, name);
                at.safeAddClientAttr(ClientAttr.CHANNELNAME, c.getName());
                at.safeAddClientAttr(ClientAttr.TARGETNAME, target.getName());
                if (target.hasBirthday()) {
                    at.safeAddClientAttr(ClientAttr.PROFILE, User.PROFILE_BIRTHDAY);
                } else {
                    at.safeAddClientAttr(ClientAttr.PROFILE, target.getGlobalProfile());
                }
                at.safeAddClientAttr(ClientAttr.LOG_TIME, (int) (d.getTime() / 1000));
                Command cmd = new Command(Command.SETPROFILE, at);
                c.sendToConnectedUsers(cmd);
            }
            return;

        } else if (profile.equals("hide")) {

            if (!hasGlobalRight(Rights.Global.CanHide)) {
                Command cmd = new Command(Command.NOPERMISSION);
                con.sendCommand(cmd);
                return;
            }

            target.setHidden(true);
            Command cmd = new Command(Command.HIDEON);
            con.sendCommand(cmd);
            return;

        } else if (profile.equals("unhide")) {

            if (!hasGlobalRight(Rights.Global.CanHide)) {
                Command cmd = new Command(Command.NOPERMISSION);
                con.sendCommand(cmd);
                return;
            }

            target.setHidden(false);
            Command cmd = new Command(Command.HIDEOFF);
            con.sendCommand(cmd);
            return;
        }
        // special profiles end


        if (target.isGuest()) {
            Command cmd = new Command(Command.NOPERMISSION);
            con.sendCommand(cmd);
            return;
        }

        if (!hasGlobalRight(Rights.Global.ServerOp, target.getDecidingGlobalRoleSqlId())) {
            Command cmd = new Command(Command.NOPERMISSION);
            con.sendCommand(cmd);
            return;
        }

        target.setRole(server.getConfig().findGlobalRoleByProfile(profile), name, auto, false);

        Date d = new Date();
        AttrList at = new AttrList();
        at.safeAddClientAttr(ClientAttr.NICKNAME, name);
        at.safeAddClientAttr(ClientAttr.TARGETNAME, target.getName());
        at.safeAddClientAttr(ClientAttr.PROFILE, target.getGlobalProfile());
        if (auto) {
            at.safeAddClientAttr(ClientAttr.PERSISTENT, 1);
        }
        at.safeAddClientAttr(ClientAttr.LOG_TIME, (int) (d.getTime() / 1000));
        Command cmd = new Command(Command.SETPROFILE, at);
        con.sendCommand(cmd);
    }

    public void channelDeOp(String channelName, String targetName, boolean auto) {
        updateIdleTime();

        Channel c = server.findChannel(channelName);
        if (c == null) {
            AttrList at = new AttrList();
            at.safeAddClientAttr(ClientAttr.CHANNELNAME, channelName);
            Command cmd = new Command(Command.NOCHANNEL, at);
            con.sendCommand(cmd);
            return;
        }

        c.deop(this, targetName, auto);
    }

    public void serverDeOp(String targetName, boolean auto) {
        updateIdleTime();

        User target = server.findUser(targetName);
        if (target == null) {

            int targetId = mySql.getUserIdOfUser(targetName);
            int targetRoleId = mySql.getGlobalRoleIdOfUser(targetName);

            if (!auto || targetId == -1 || targetRoleId == -1) {
                AttrList at = new AttrList();
                at.safeAddClientAttr(ClientAttr.TARGETNAME, targetName);
                Command cmd = new Command(Command.NOTARGET, at);
                con.sendCommand(cmd);
                return;
            }

            if (!hasGlobalRight(Rights.Global.ServerOp, targetRoleId)) {
                Command cmd = new Command(Command.NOPERMISSION);
                con.sendCommand(cmd);
                return;
            }

            GlobalRole newRole = server.getConfig().getDefaultRegGlobalRole();
            mySql.updateGlobalRoleOfUser(targetId, newRole.getSqlId(), name);

            Date d = new Date();
            AttrList at = new AttrList();
            at.safeAddClientAttr(ClientAttr.NICKNAME, name);
            at.safeAddClientAttr(ClientAttr.TARGETNAME, targetName);
            at.safeAddClientAttr(ClientAttr.PROFILE, newRole.getProfile());

            at.safeAddClientAttr(ClientAttr.PERSISTENT, 1);
            at.safeAddClientAttr(ClientAttr.LOG_TIME, (int) (d.getTime() / 1000));
            Command cmd = new Command(Command.SETPROFILE, at);
            con.sendCommand(cmd);
        }

        if (!hasGlobalRight(Rights.Global.ServerOp, target.getDecidingGlobalRoleSqlId())) {
            Command cmd = new Command(Command.NOPERMISSION);
            con.sendCommand(cmd);
            return;
        }

        if (this == target && auto) {
            Command cmd = new Command(Command.NOPERMISSION);
            con.sendCommand(cmd);
            return;
        }

        GlobalRole newRole;
        if (target.isGuest()) {
            newRole = server.getConfig().getDefaultGlobalRole();
        } else {
            newRole = server.getConfig().getDefaultRegGlobalRole();
        }

        if (target.hasBirthday()) {
            target.setBirthday(false);
        }

        target.setRole(newRole, name, auto, false);

        Date d = new Date();
        AttrList at = new AttrList();
        at.safeAddClientAttr(ClientAttr.NICKNAME, name);
        at.safeAddClientAttr(ClientAttr.TARGETNAME, target.getName());
        at.safeAddClientAttr(ClientAttr.PROFILE, target.getGlobalProfile());
        if (auto) {
            at.safeAddClientAttr(ClientAttr.PERSISTENT, 1);
        }
        at.safeAddClientAttr(ClientAttr.LOG_TIME, (int) (d.getTime() / 1000));
        Command cmd = new Command(Command.SETPROFILE, at);
        con.sendCommand(cmd);
    }

    public void killChannel(String channelName) {
        Channel c = server.findChannel(channelName);
        if (c == null) {
            AttrList at = new AttrList();
            at.safeAddClientAttr(ClientAttr.CHANNELNAME, channelName);
            Command cmd = new Command(Command.NOCHANNEL, at);
            con.sendCommand(cmd);
            return;
        }

        c.kill(this);
    }

    public void getChannelLog(int logTime) {
        Iterator<Channel> iter = connectedChannels.iterator();
        if (!iter.hasNext()) {
            Command cmd = new Command(Command.NOCHANNEL);
            con.sendCommand(cmd);
            return;
        }

        Channel c = iter.next();

        c.getEventLog(this, logTime);
    }

    public void doRehash() {

        if (!hasGlobalRight(Rights.Global.AdministrateServer)) {
            Command cmd = new Command(Command.NOPERMISSION);
            con.sendCommand(cmd);
            return;
        }

        server.rehash();

        Command cmd = new Command(Command.DONE);
        con.sendCommand(cmd);
    }

    public void getServerBanList() {

        if (!hasGlobalRight(Rights.Global.ViewServerBans)) {
            Command cmd = new Command(Command.NOPERMISSION);
            con.sendCommand(cmd);
            return;
        }

        List<BanInfo> banlist = server.getBanList();

        AttrList at = new AttrList();

        Iterator<BanInfo> iter = banlist.iterator();
        while (iter.hasNext()) {
            BanInfo bi = iter.next();

            at.safeAddClientAttr(ClientAttr.NICKNAME, bi.name);

            if (hasGlobalRight(Rights.Global.ViewIP)) {
                at.safeAddClientAttr(ClientAttr.BAN_IPNET, bi.getRawIp());
                if (bi.ipSize != 32) {
                    at.safeAddClientAttr(ClientAttr.BAN_IPSIZE, bi.ipSize);
                }
            }

            at.safeAddClientAttr(ClientAttr.BAN_TIMELEFT, bi.getTimeLeft());
            at.safeAddClientAttr(ClientAttr.BAN_BANNER, bi.banner);
            //at.safeAddClientAttr(ClientAttr.IDENT, ""); 
        }

        Command cmd = new Command(Command.BANLIST, at);
        con.sendCommand(cmd);
    }

    public void getChannelBanList(String channelName) {
        Channel c = server.findChannel(channelName);
        
        ServerLog.log("ADZ - User.java->getChannelBanList:channelName="+channelName+":c="+c);
        
        if (c == null) {
            AttrList at = new AttrList();
            at.safeAddClientAttr(ClientAttr.CHANNELNAME, channelName);
            Command cmd = new Command(Command.NOCHANNEL, at);
            con.sendCommand(cmd);
            return;
        }

        c.getBanList(this);
    }

    public void getServerAutoOpList() {
        ServerLog.log("ADZ - User.java->getServerAutoOpList");

        if (!hasGlobalRight(Rights.Global.ViewServerOps)) {
            Command cmd = new Command(Command.NOPERMISSION);
            con.sendCommand(cmd);
            return;
        }

        List<AutoOpInfo> autooplist = server.getAutoOpList();

        AttrList at = new AttrList();

        Iterator<AutoOpInfo> iter = autooplist.iterator();
        while (iter.hasNext()) {
            AutoOpInfo aoi = iter.next();

            at.safeAddClientAttr(ClientAttr.NICKNAME, aoi.name);
            at.safeAddClientAttr(ClientAttr.PROFILE, aoi.profile);
            at.safeAddClientAttr(ClientAttr.BAN_BANNER, aoi.oper);
        }

        Command cmd = new Command(Command.BANLIST, at);
        con.sendCommand(cmd);
    }

    public void getChannelAutoOpList(String channelName) {
        ServerLog.log("ADZ - User.java->getServerAutoOpList:channelName="+channelName);
        Channel c = server.findChannel(channelName);
        if (c == null) {
            AttrList at = new AttrList();
            at.safeAddClientAttr(ClientAttr.CHANNELNAME, channelName);
            Command cmd = new Command(Command.NOCHANNEL, at);
            con.sendCommand(cmd);
            return;
        }

        c.getAutoOpList(this);
    }

    public void getChannelList() {
        AttrList at = new AttrList();

        Iterator<Channel> iter = server.getChannelIterator();
        while (iter.hasNext()) {
            Channel c = iter.next();

            if (c.getProfile() == Channel.Profile.VIP
                    && !hasGlobalRight(Rights.Global.JoinVIPChannels)) {
                continue;
            }

            if (c.getProfile() == Channel.Profile.ADMIN
                    && !hasGlobalRight(Rights.Global.JoinAdminChannels)) {
                continue;
            }

            c.getChannelInfo(at);
        }
        Command cmd = new Command(Command.CHANNELLIST, at);
        con.sendCommand(cmd);

    }

    public void setAccount(String regName, String password, String email) {

        String curName = this.name;
        if (isGuest()) {
            curName = this.name.substring(1);
        }

        if (!regName.equalsIgnoreCase(curName)) {
            con.sendCommand(new Command(Command.REGNAMEMATCH));
            return;
        }

        if (isGuest()) {

            if (mySql.isNameRegistered(regName)) {
                con.sendCommand(new Command(Command.REGNAMETAKEN));
                return;
            }

            if (!mySql.registerUser(regName, password, autoRole, autoRoleBy, userInfo, email)) {
                AttrList at = new AttrList();
                at.safeAddClientAttr(ClientAttr.EXEC, "Unknown database error!");
                con.sendCommand(new Command(Command.FAILED, at));
                return;
            }

            String oldName = this.name;
            this.name = curName;
            this.lcName = this.name.toLowerCase();
            authenticate(regName, password);

            setRole(server.getConfig().getDefaultRegGlobalRole(), name, true, false);

            AttrList at = new AttrList();
            at.safeAddClientAttr(ClientAttr.PASSWORD, password);
            con.sendCommand(new Command(Command.REGCREATED, at));

            Iterator<Channel> iter = connectedChannels.iterator();
            while (iter.hasNext()) {
                iter.next().resendNickList();
            }

            at = new AttrList();
            at.safeAddClientAttr(ClientAttr.NICKNAME, oldName);
            at.safeAddClientAttr(ClientAttr.TARGETNAME, this.name);
            Command cmd = new Command(Command.CHANGEDNICKNAME, at);

            Set<User> users = new HashSet<User>();
            iter = connectedChannels.iterator();
            while (iter.hasNext()) {
                Iterator<User> iter2 = iter.next().getUserIterator();
                while (iter2.hasNext()) {
                    users.add(iter2.next());
                }
            }
            Iterator<User> iter2 = users.iterator();
            while (iter2.hasNext()) {
                iter2.next().getConnection().sendCommand(cmd);
            }

        } else {
            if (sqlId == -1) {
                AttrList at = new AttrList();
                at.safeAddClientAttr(ClientAttr.EXEC, "Unknown database error! (1)");
                con.sendCommand(new Command(Command.FAILED, at));
                return;
            }

            if (!this.email.toLowerCase().equals(email.toLowerCase())) {
                con.sendCommand(new Command(Command.REGWRONGEMAIL));
                return;
            }

            if (!mySql.changePasswordOfUser(sqlId, password)) {
                AttrList at = new AttrList();
                at.safeAddClientAttr(ClientAttr.EXEC, "Unknown database error! (2)");
                con.sendCommand(new Command(Command.FAILED, at));
                return;
            }

            mySql.changePasswordOfUser(sqlId, password);

            AttrList at = new AttrList();
            at.safeAddClientAttr(ClientAttr.PASSWORD, password);
            con.sendCommand(new Command(Command.REGPWCHANGED, at));
        }
    }

    public void getNickList(String channelName) {
        AttrList at = new AttrList();
        Iterator<User> iter;

        if (channelName != null) {
            Channel c = server.findChannel(channelName);
            if (c == null) {
                at.safeAddClientAttr(ClientAttr.CHANNELNAME, channelName);
                Command cmd = new Command(Command.NOCHANNEL, at);
                con.sendCommand(cmd);
                return;
            } else {

                c.getChannelInfo(at);

                iter = c.getUserIterator();
                while (iter.hasNext()) {
                    User u = iter.next();
                    if (u.isHidden()) {
                        continue;
                    }
                    at.safeAddClientAttr(ClientAttr.NICKNAME, u.getName());

                    try {
                        at.add(c.getChannelUserPerms(u).toAttr(ClientAttr.PERMS));
                    } catch (Exception ex) {
                    }
                    at.safeAddClientAttr(ClientAttr.PROFILE, c.getUserChannelProfile(u));
                }
                Command cmd = new Command(Command.NICKLIST, at);
                con.sendCommand(cmd);

            }
        } else {
            iter = server.getUserIterator();
            while (iter.hasNext()) {
                User u = iter.next();
                if (u.isHidden()) {
                    continue;
                }
                at.safeAddClientAttr(ClientAttr.NICKNAME, u.getName());
                try {
                    at.add(u.getGlobalPerms().toAttr(ClientAttr.PERMS));
                } catch (Exception ex) {
                }
                at.safeAddClientAttr(ClientAttr.PROFILE, u.getGlobalProfile());
            }
            Command cmd = new Command(Command.NICKLIST, at);
            con.sendCommand(cmd);
        }

    }
}
